package com.chuhe.starry.websocket.netty;

import com.chuhe.common.utils.AppConfig;
import com.chuhe.common.utils.StringTools;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class NettyWebSocketStarter implements ApplicationRunner {
    @Autowired
    private AppConfig appConfig;
    @Autowired
    private HandlerWebSocket handlerWebSocket; //这里必须要注入，否则得不到springboot容器管理

    // 核心配置：使用单线程池异步启动 Netty（使用 Spring 管理的线程池，避免手动创建）
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    // Netty 线程组（workerGroup 不指定线程数，使用默认值）
    private EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    private EventLoopGroup workerGroup = new NioEventLoopGroup(); // 默认线程数为 CPU核心数*2

    /**
     * 销毁方法：关闭所有资源
     */
    @PreDestroy
    public void destroy() {
        // 关闭异步线程池
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        // 优雅关闭 Netty 线程组
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        log.info("关闭 ws server 成功");
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        executor.submit(() -> {
            try {
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .option(ChannelOption.SO_KEEPALIVE, true)
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                ChannelPipeline pipeline = socketChannel.pipeline();
                                // 心跳检测：60秒无读事件则触发空闲状态
                                pipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
                                // HTTP 相关处理器
                                pipeline.addLast(new HttpServerCodec());
                                pipeline.addLast(new ChunkedWriteHandler());
                                pipeline.addLast(new HttpObjectAggregator(64 * 1024));
                                // 心跳处理器
                                pipeline.addLast(new HandlerHeartBeat());
                                // WebSocket 协议升级（注意路径和参数）
                                pipeline.addLast(new WebSocketServerProtocolHandler(
                                        "/ws",          // WebSocket 路径
                                        null,          // 子协议（可选）
                                        true,          // 允许自动压缩
                                        64 * 1024,     // 最大帧缓冲区大小
                                        true,          // 允许拆分大帧
                                        true,          // 保留原始帧字节缓冲区
                                        10000L         // 握手超时时间（毫秒）
                                ));
                                // 业务处理器
                                pipeline.addLast(handlerWebSocket);
                            }
                        });

                // 绑定端口并启动服务端
                Integer wsPort = appConfig.getWsPort();
                String wsPortStr = System.getProperty("ws.port");
                if(!StringTools.isEmpty(wsPortStr)){
                    wsPort = Integer.parseInt(wsPortStr);
                }
                ChannelFuture channelFuture = serverBootstrap.bind(wsPort).sync();
                log.info("Netty服务端启动成功,端口:{}", wsPort);

                // 阻塞当前线程（异步线程），确保 Netty 持续运行
                channelFuture.channel().closeFuture().sync();
            } catch (Exception e) {
                log.error("Netty 服务端启动失败", e);
                // 若启动失败，关闭资源避免泄漏
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
                executor.shutdownNow();
            }
        });
    }
}